package com.sxt.server.server;

import java.io.IOException;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

import org.springframework.stereotype.Component;

import lombok.extern.slf4j.Slf4j;

/**
 * WebSocket服务类
 * 
 * 前端调用方式： //指定要连接的服务器地址与端口建立连接 websocket = new
 * WebSocket("ws://192.168.1.3:9090/ws/server/1");
 * 消费十分频繁，websocket经常出现与前端断开连接导致推送失败挂掉
 * 
 * @author 罗林
 */
@Slf4j
@ServerEndpoint(value = "/ws/server/{sid}")
@Component
public class WebSocketServer {

	//@PostConstruct
	public void init() {
		System.out.println("websocket 加载");
	}

	// private static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
	// 用来记录当前在线连接数。应该把它设计成线程安全的
	private static final AtomicInteger OnlineCount = new AtomicInteger(0);
	// concurrent包的线程安全Set，用来存放每个客户端对应的Session对象。
	// private static CopyOnWriteArraySet<Session> SessionSet = new CopyOnWriteArraySet<Session>();
	// concurrent包的线程安全Set，用来存放每个客户端对应的MyWebSocket对象。
	private static CopyOnWriteArraySet<WebSocketServer> WebSocketSet = new CopyOnWriteArraySet<WebSocketServer>();
	// 与某个客户端的连接会话，需要通过它来给客户端发送数据
	private Session session;
	// 接收sid
	private String sid = "";

	/**
	 * 连接建立成功调用的方法
	 */
	@OnOpen
	public void onOpen(Session session, @PathParam("sid") String sid) {
		this.session = session;
		this.sid = sid;
		// SessionSet.add(session);
		WebSocketSet.add(this);

		int cnt = OnlineCount.incrementAndGet(); // 在线数加1
		log.info("有连接加入，当前连接数为：{}", cnt);
		this.sendMessage("连接成功");
	}

	/**
	 * 连接关闭调用的方法
	 */
	@OnClose
	public void onClose() {
		WebSocketSet.remove(this);
		int cnt = OnlineCount.decrementAndGet();// 在线数减1
		log.info("有连接关闭，当前连接数为：{}", cnt);
	}

	/**
	 * 收到客户端消息后调用的方法
	 *
	 * @param message 客户端发送过来的消息
	 */
	@OnMessage
	public void onMessage(String message, Session session) {
		log.info("来自客户端的消息：{}", message);
		this.sendMessage("收到消息，消息内容：" + message);
	}

	/**
	 * 出现错误
	 * 
	 * @param session
	 * @param error
	 */
	@OnError
	public void onError(Session session, Throwable error) {
		log.error("发生错误：{}，Session ID： {}", error.getMessage(), session.getId());
		error.printStackTrace();
	}

	/**
	 * 实现服务器主动推送
	 */
	public void sendMessage(String message){
		// 加同步锁，解决多线程下发送消息异常关闭
		synchronized (this.session) {
			// getBasicRemote是阻塞式的
			// this.session.getBasicRemote().sendText(message);
			// 是非阻塞式的
			this.session.getAsyncRemote()
					.sendText(String.format("%s (From Server，Session ID=%s)", message, this.session.getId()));
			// 是阻塞式的，一次发送全部消息
			// session.getBasicRemote().sendText(String.format("%s (From Server，Session
			// ID=%s)",message,session.getId()), false);
			// 是阻塞式的，可以发送消息中的部分消息
			// session.getBasicRemote().sendText(String.format("%s (From Server，Session
			// ID=%s)",message,session.getId()), true);
		}

	}

	/**
	 * 群发自定义消息
	 * 
	 * @param message
	 * @throws IOException
	 */
	public static void BroadCastInfo(String message, @PathParam("sid") String sid){
		for (WebSocketServer item : WebSocketSet) {
			// 这里可以设定只推送给这个sid的，为null则全部推送
			try {
				if (sid == null) {
					item.sendMessage(message);
				} else if (item.sid.equals(sid)) {
					item.sendMessage(message);
					return;//结束当前方法
				}
			} catch (Exception e) {
				// TODO: handle exception
				continue;// 跳过本次循环体中余下尚未执行的语句
			}
		}
	}
}
